Modification Manuelle de l'IAT


Rien ne vaut un peu de pratique pour mieux comprendre. Le programme cible ne contient que deux fonctions MessageBoxA de USER32.dll et ExitProcess de KERNEL32.dll. C'est juste un petit programme Hello Word. On va lui ajouter les éléments suivants:

Oups, avant tout je précise que les fonctions que je vais lui rajouter je ne les utiliserai pas, c'est pas mon but pour l'instant. L'objectif c'est seulement de réussir à reconstruire un IAT valide possédant de nouvelles fonctions. Comment savoir alors si on a réussit où non ? C'est simple si après votre modification le programme redémarre correctement, c'est bon. Dans le cas contraire vous n'allez pas tarder à comprendre que quelque chose va de travers.

- GetModuleHandleA (de KERNEL32.dll)
- FT_Exit8 (de KERNEL32.dll) ------------> Ordinal
- ShellExecuteA (de SHELL32.dll)

Pour ce qui est de "FT_Exit8", on pourrait l'importé normalement, mais on va plutôt l'importer à partir de son n°Ordinal. Comme ça on aura 3 cas différents, c'est mieux pour tout comprendre. A oui au fait son n°Ordinal c'est 10Ah (Voir SoftIce : -exp)

Un conseil avisé, avant de vous lancer dans l'ajout de fonctions prenez toujours le temps de rechercher les noms EXACTES des DLL et des fonctions. Parce que par exemple mettre le nom "messageboxa" au lieu de "MessageBoxA", vous obligera à simplement corriger cette petite erreur, mais par contre mettez un "MessageBox" au lieu d'un "MessageBoxA" et là vous êtes bon pour décaler tout dans l'IAT et donc tout réadresser, tout refaire en fait. Et si vous regardez les Ref Win32 aucune fonction n'est présentée avec les extensions AINSI(A) ou UNICODE(W). Donc un coup de W32Dasm sur un prog ou SoftIce sont plutôt bien venus avant de passer à l'attaque.




I - ON OBSERVE :

On décortique le programme cible d'abord avec l'excellant ProcDump:

Import Table : 2010
Import Address Table : 2000 (IAT)

  Virtual Size Virtual Offset Raw Size Raw Offset Characteristics
.text 00000028 00001000 00000200 00000400 60000020
.rdata 00000092
00002000 00000200 00000600 40000040
.data 00000024 00003000 00000200 00000800 C0000040

1 - D'abord on nous dit que la section qui représente l'IAT commence en 2000h c'est donc .rdata
2 - Le point d'entrée dans cette section est en 2010h. Le point d'entrée de l'IAT c'est toujours la structure IMAGE_IMPORT_DESCRIPTOR. Ce qui signifie que le premier DWORD où débute IMAGE_IMPORT_DESCRIPTOR est en 2010h

Maintenant il faut bien se souvenir d'une chose, c'est que W32Dasm ou HexWorkShop ne se servent pas de RVA (Virtual Offset), ils utilisent un adressage directe (Raw Offset) Par contre toutes les adresses contenues dans l'IAT sont des RVA. Ce qui complique notre affaire.

Ca signifie qu'en utilisant HexWorkShop, l'IAT commence en 00000600 (et fini en 00000800) l'IMAGE_IMPORT_DESCRIPTOR sera donc en 00000610h (Il suffit de garder le même déplacement, et d'effectuer un changement de base entre ces deux représentations)


Vue par HexWorkShop:

00000600 7620 0000 0000 0000 5C20 0000 0000 0000 v ......\ ......
00000610
5420 0000
0000 0000 0000 0000 6A20 0000 T ..........j ..
00000620 0820 0000 4C20 0000 0000 0000 0000 0000 . ..L ..........
00000630 8420 0000 0020 0000 0000 0000 0000 0000 . ... ..........
00000640 0000 0000 0000 0000 0000 0000 7620 0000 ............v ..
00000650 0000 0000 5C20 0000 0000 0000 BB01 4D65 ....\ ........Me
00000660 7373 6167 6542 6F78 4100 5553 4552 3332 ssageBoxA.USER32
00000670 2E64 6C6C 0000 7500 4578 6974 5072 6F63 .dll..u.ExitProc
00000680 6573 7300 4B45 524E 454C 3332 2E64 6C6C ess.KERNEL32.dll
00000690 0000 0000 0000 0000 0000 0000 0000 0000 ................
000006A0 0000 0000 0000 0000 0000 0000 0000 0000 ................
000006B0 0000 0000 0000 0000 0000 0000 0000 0000 ................
000006C0 0000 0000 0000 0000 0000 0000 0000 0000 ................
000006D0 0000 0000 0000 0000 0000 0000 0000 0000 ................
000006E0 0000 0000 0000 0000 0000 0000 0000 0000 ................
000006F0 0000 0000 0000 0000 0000 0000 0000 0000 ................
00000700 0000 0000 0000 0000 0000 0000 0000 0000 ................
00000710 0000 0000 0000 0000 0000 0000 0000 0000 ................
000007......                  
000007F0 0000 0000 0000 0000 0000 0000 0000 0000 ................

 

Un peu vide vous trouvez pas.... Enfin c'est une autre histoire quand un programme possède plus de 150 fonctions au lieu de 2 comme ici.

En 610h on retrouve le point d'entrée dans l'IAT qui est le premier dword de la structure IMAGE_IMPORT_DESCRIPTOR. La taille de cette structure étant de 5 dword, je vous les ai surlignés. Le reste de ce qui est souligné sont aussi des structures IMAGE_IMPORT_DESCRIPTOR.

L'IAT possède toujours autant d'IMAGE_IMPORT_DESCRIPTOR qu'il y a de DLL importées par votre programme + 1 IMAGE_IMPORT_DESCRIPTOR remplit de NULL pour notifier le programme de la fin de ce groupe de structures.
Pourquoi y en a autant ? C'est parce que cette structure est justement celle qui sert à conserver toutes les info à propos d'une DLL donnée. Souvenez-vous de sa définition :

IMAGE_IMPORT_DESCRIPTOR <>
- OriginalFirstThunk dd ? <------------------------------ C'est un RVA qui pointe sur la structure ORIGINAL FIRST THUNK
- TimeDateStamp dd ? <---------------------------------- Généralement mis à 0 comme ici
- ForwarderChain dd ? <----------------------------------- Réservé (mis à 0FFFFFFFFh si on suit la norme. Mais c'est pas le cas ici)
- Name1 dd ? <----------------------------------------------- RVA pointant sur le nom de la DLL
- FirstThunk dd ? <------------------------------------------ C'est un RVA qui pointe sur la structure FIRST THUNK
IMAGE_IMPORT_DESCRIPTOR ENDS


Prenez la première structure IMAGE_IMPORT_DESCRIPTOR, regardez son 4e DWORD (Name1 donc) ce DWORD vaut 6A20 0000.
Je le remet dans le format Intel ce qui donne 0000 206A. Maintenant souvenez vous que toutes ces adresses sont des RVA donc elle utilisent comme base VirtualOffset (2000) alors que HexWorkShop réalise un adressage à partir du Raw Offset (600) donc 0000 206A représente 0000 066A dans notre changement de base. Et que trouve t'on en 66Ah,...... la chaine de caractères USER32.dll (ouhhhoouh.... gagné!!!)

Le premier IMAGE_IMPORT_DESCRIPTOR concerne donc USER32 et ses Fonctions. Le second concerne KERNEL32 et ses Fonctions vous l'aviez deviné.
Maintenant comment retrouver ses fonctions justement. Normalement c'est le membre OriginalFirstThunk qui est utilisé mais parfois il peut être NULL (ce qui normalement ne doit pas arriver) dans ce cas on prend FirstThunk.

Ces deux membres pointent sur deux structures distinctent mais qui contiennent exactement les même info.

ORIGINAL_FIRST_THUNK et FIRST_THUNK (A oui les structures je les mets toujours en majuscules alors que les membres je les laisse toujours en minuscule, sinon on va pas s'en sortir) Mes deux structures ORINAL_FIRST_THUNK et FIRST_THUNK sont normalement appelées toutes les deux IMAGE_THUNK_DATA mais je n'utiliserai plus ce terme, car si il décrit bien le type de structure à laquelle on a à faire, il est malheureusement peu explicite quant à savoir si on parle des FirstThunk ou bien des OriginalFirstThunk. Donc pour ma part, je les appelle toujours ainsi pour faire la différence, mais en sachant très bien que ce ne sont pas leurs vrais noms.


ORIGINAL_FIRST_THUNK<>
- RVA ImageImportByName1 <-------------------------------------- RVA qui nous amène à une structure IMAGE_IMPORT_BY_NAME
- ..............
- RVA ImageImportByName n
ORIGINAL_FIRST_THUNK ENDS


FIRST_THUNK est exactement identique.
Pour une DLL donnée, il y aura autant de RVA que cette DLL possède de fonctions + 1 RVA NULL pour terminer la structure.

 

00000600 7620 0000 0000 0000 5C20 0000 0000 0000 v ......\ ......
00000610
5420 0000
0000 0000 0000 0000 6A20 0000 T ..........j ..
00000620 0820 0000 4C20 0000 0000 0000 0000 0000 . ..L ..........
00000630 8420 0000 0020 0000 0000 0000 0000 0000 . ... ..........
00000640 0000 0000 0000 0000 0000 0000 7620 0000 ............v ..
00000650 0000 0000 5C20 0000 0000 0000 BB01 4D65 ....\ ........Me
00000660 7373 6167 6542 6F78 4100 5553 4552 3332 ssageBoxA.USER32
00000670 2E64 6C6C 0000 7500 4578 6974 5072 6F63 .dll..u.ExitProc
00000680 6573 7300 4B45 524E 454C 3332 2E64 6C6C ess.KERNEL32.dll
00000690 0000 0000 0000 0000 0000 0000 0000 0000 ................
000006A0 0000 0000 0000 0000 0000 0000 0000 0000 ................
000006B0 0000 0000 0000 0000 0000 0000 0000 0000 ................
000006C0 0000 0000 0000 0000 0000 0000 0000 0000 ................
000006D0 0000 0000 0000 0000 0000 0000 0000 0000 ................
000006E0 0000 0000 0000 0000 0000 0000 0000 0000 ................
000006F0 0000 0000 0000 0000 0000 0000 0000 0000 ................
00000700 0000 0000 0000 0000 0000 0000 0000 0000 ................
00000710 0000 0000 0000 0000 0000 0000 0000 0000 ................
000007......                  
000007F0 0000 0000 0000 0000 0000 0000 0000 0000 ................

Reprenons le premier IMAGE_IMPORT_DESCRIPTOR (Taille 5 DWORDs) son premier DWORD est donc un RVA qui pointe sur une structure ORIGINAL_FIRST_THUNK. 5420 0000 -->0000 2054 --> 0000 000654

En 654h on trouve le DWORD 5C20 0000 suivit d'un DWORD 0000 0000 NULL. Cà signifie qu'en 654h on rencontre le début de la structure ORIGINAL_FIRST_THUNK mais qu'elle ne possède qu'un seul membre donc qu'une seule fonction.

Maintenant le contenu de 654 (le contenu de OFT) est lui-même un RVA qui pointe sur une structure IMAGE_IMPORT_BY_NAME :


IMAGE_IMPORT_BY_NAME STRUCT
Hint dw ? ; <--------------------------------------------------n°ORDINAL (Word donc taille 2)
Name1 db ? ; <----------------------------------------------Nom de la fonction
IMAGE_IMPORT_BY_NAME ENDS



Le contenu de 654 est 5C20 0000 --> 0000205C --> 0000 065C
Et que trouve-t-on en 65Ch, d'abord le N°ordinal de la fonction sur un WORD, immédiatement suivit de la fonction correspondante.

00000600 7620 0000 0000 0000 5C20 0000 0000 0000 v ......\ ......
00000610
5420 0000
0000 0000 0000 0000 6A20 0000 T ..........j ..
00000620 0820 0000 4C20 0000 0000 0000 0000 0000 . ..L ..........
00000630 8420 0000 0020 0000 0000 0000 0000 0000 . ... ..........
00000640 0000 0000 0000 0000 0000 0000 7620 0000 ............v ..
00000650 0000 0000 5C20 0000 0000 0000 BB01 4D65 ....\ ........Me
00000660 7373 6167 6542 6F78 4100 5553 4552 3332 ssageBoxA.USER32
00000670 2E64 6C6C 0000 7500 4578 6974 5072 6F63 .dll..u.ExitProc
00000680 6573 7300 4B45 524E 454C 3332 2E64 6C6C ess.KERNEL32.dll
00000690 0000 0000 0000 0000 0000 0000 0000 0000 ................
000006A0 0000 0000 0000 0000 0000 0000 0000 0000 ................
000006B0 0000 0000 0000 0000 0000 0000 0000 0000 ................
000006C0 0000 0000 0000 0000 0000 0000 0000 0000 ................
000006D0 0000 0000 0000 0000 0000 0000 0000 0000 ................
000006E0 0000 0000 0000 0000 0000 0000 0000 0000 ................
000006F0 0000 0000 0000 0000 0000 0000 0000 0000 ................
00000700 0000 0000 0000 0000 0000 0000 0000 0000 ................
00000710 0000 0000 0000 0000 0000 0000 0000 0000 ................
000007......                  
000007F0 0000 0000 0000 0000 0000 0000 0000 0000 ................


Maintenant un détail, certaines fonctions sont importées uniquement By Ordninal (ici elles sont toutes importées By Name) Dans ce cas, elles n'ont donc aucune structure IMAGE_IMPORT_BY_NAME et le N°Ordinal est donc placé en lieu et place du RVA de ORIGINAL_FIRST_THUNK (et de FIRST_THUNK puisqu'ils sont jumeaux)

 

00000600 7620 0000 0000 0000 5C20 0000 0000 0000 v ......\ ......<------ FIRST_THUNK
00000610
5420 0000
0000 0000 0000 0000 6A20 0000 T ..........j ..<------ IMAGE_IMPORT_DECRIPTOR
00000620 0820 0000 4C20 0000 0000 0000 0000 0000 . ..L ..........
00000630 8420 0000 0020 0000 0000 0000 0000 0000 . ... ..........
00000640 0000 0000 0000 0000 0000 0000 7620 0000 ............v ..<------ ORIGINAL_FIRST_THUNK
00000650 0000 0000 5C20 0000 0000 0000 BB01 4D65 ....\ ........Me
00000660 7373 6167 6542 6F78 4100 5553 4552 3332 ssageBoxA.USER32 <------- IMAGE_IMPORT_BY_NAME
00000670 2E64 6C6C 0000 7500 4578 6974 5072 6F63 .dll..u.ExitProc
00000680 6573 7300 4B45 524E 454C 3332 2E64 6C6C ess.KERNEL32.dll
00000690 0000 0000 0000 0000 0000 0000 0000 0000 ................
000006A0 0000 0000 0000 0000 0000 0000 0000 0000 ................
000006B0 0000 0000 0000 0000 0000 0000 0000 0000 ................
000006C0 0000 0000 0000 0000 0000 0000 0000 0000 ................
000006D0 0000 0000 0000 0000 0000 0000 0000 0000 ................
000006E0 0000 0000 0000 0000 0000 0000 0000 0000 ................
000006F0 0000 0000 0000 0000 0000 0000 0000 0000 ................
00000700 0000 0000 0000 0000 0000 0000 0000 0000 ................
00000710 0000 0000 0000 0000 0000 0000 0000 0000 ................
000007......                  
000007F0 0000 0000 0000 0000 0000 0000 0000 0000 ................

Quelques détailles:

Vous voyez qu'ici le point d'entrée dans l'IAT n'est pas en début de section, et bien ce n'est pas incompatible du tout, toutes ces structures peuvent êtres mises dans l'ordre que vous souhaitez. Rien ne vous empèche de mettre IMAGE_IMPORT_DESCRIPTOR dès le début, et d'ailleurs je préfère grandement. Il faudra juste aligner la valeur de Import Table sur celle de Import Address Table (Vue dans ProcDump) Du moment que tous les RVA contenus dans cette section soient correctement réadressés, l'IAT restera valide.
Autre chose, si vous regardez bien, la chaine de caractère USER32.dll et terminée non pas par un byte NULL mais pas deux, idem pour KERNEL32.dll, et bien un seul aurait suffit, c'est juste que le linker de Masm (ben oui j'ai créée la cible Hello.exe avec Masm) suit ses propres règles de construction, mais en mettre un seul ne provoquera pas d'erreur. De même, Masm construit toujours l'IAT en commençant par FIRST_THUNK, IMAGE_IMPORT_DESCRIPTOR, ORIGINAL_FIRST_THUNK, IMAGE_IMPORT_BY_NAME, mais d'autres linkers le construisent autrement. D'ailleurs ce serait un moyen de déterminer avec quel langage un programme a été écrit.



II - ON AGIT :

On va donc réécrire l'IAT avec nos nouvelles fonctions. Perso, je préfère mettre les IMAGE_IMPORT_DESCRIPTOR en début de section.

IMAGE_IMPORT_DESCRIPTOR:
On utilise combien de DLL ? .... 3 (USER32.dll, KERNEL32.dll, et SHELL32.dll)
Ce qui fait 3 IMAGE_IMPORT_DESCRIPTOR + 1 VIDE.
(3+1) * 5 DWORD = 20 DWORD = 80 BYTE

IMAGE_THUNK_DATA (ORIGINAL_FIRST_THUNK + FIRST_THUNK):
KERNEL32.dll (ExitProcess, GetModuleHandleA, FT_Exit8) 3 DWORD + 1 NULL
USER32.dll (MessageBoxA) 1 DWORD + 1 NULL
SHELL32.dll(ShellExecute) 1 DWORD + 1 NULL
soit 8 DWORD (seulement pour ORIGINAL_FIRST_THUNK mais autant pour FIRST_THUNK)
16 DWORD = 84 BYTES

IMAGE_IMPORT_BY_NAME

On compte le nb de caractères +1 pour chaque DLL = 36 BYTES si je ne me suis pas trompé.
On compte le nb de caractères +1 pour chaque fonction (sauf FT_Exit8 car on a dit qu'on l'importait by ordinal et non pas by name) = 55 BYTES
On compte les n°Ordinaux associés à ces noms de fonction (donc toujours pas FT_Exit8) 5 fonctions * 1 WORD = 10 BYTES
101 BYTE

IMAGE_IMPORT_DESCRIPTOR va être au début de la section, donc en 600h
ORIGINAL_FIRST_THUNK le suit donc il sera en 600h+(80d BYTES) = 650h
FIRST_THUNK le suit donc il sera en 650h + (8d*4 BYTES) = 670h
IMAGES_IMPORT_BY_NAME suit en 670h + (8d*4 BYTES) = 690h


Peu importe quelle DLL on écrit en premier, peu importe l'ordre dans lequel on écrit ses fonctions aussi, et même, on pourrait bien tout mêlanger.... fonctions et DLL en bordel, tout fonctionnerait encore du moment que Name1 soit correctement adressé sur le bon nom de DLL, et que OriginalFirstThunk et FirstThunk soient aussi correctement adressés pour chaque fonction. Une seule chose, chaque fonction doit garder son propre n°Ordinal 1WORD devant elle.
Le membre ForwarderChain qui normalement doit être mis à 0FFFFFFFFh est à 0 ici, donc je vais lui remettre sa valeur normale. C'est en plus un exellent point de repère dans la structure IMAGE_IMPORT_DESCRIPTOR.

Je n'ai pas recherché les N°Ordinaux des fonctions ShellExecuteA et GetModuleHandleA donc je vais les laisser à 0000, ça ne pose pas de problème puisque je les importe By Name, mais bon pour être rigoureux il faudrait les placer quand même. Donc n'oubliez pas de laisser un WORD NULL devant elles pour que le format reste viable (sinon vous obtiendrez une structure IMAGE_IMPORT_BY_NAME incorrecte). Tout cette table est réécrite en commençant par replacer les chaînes de caractères représentant les noms des DLLs et de leurs fonctions. Ensuite seulement il est possible de savoir quoi mettre dans le reste de la table.

00000600     0000 0000 FFFF FFFF      
00000610         0000 0000 FFFF FFFF  
00000620             0000 0000  
00000630 FFFF FFFF         0000 0000  
00000640 0000 0000 0000 0000 0000 0000 0000 0000  
00000650
Fonct
ion n°1A
Fonct
ion n°2A
Fonct
ion n°3A 0000 0000  
00000660
Fonct
ion n°1B 0000 0000
Fonct
ion n°1C 0000 0000  
00000670             0000 0000  
00000680     0000 0000     0000 0000  
00000690 7500 4578 6974 5072 6F63 6573 7300 0000 u.ExitProcess...
000006A0 4765 744D 6F64 756C 6548 616E 646C 6541 GetModuleHandleA
000006B0 004B 4552 4E45 4C33 322E 646C 6C00 BB01 .KERNEL32.dll...
000006C0 4D65 7373 6167 6542 6F78 4100 5553 4552 MessageBoxA.USER
000006D0 3332 2E64 6C6C 0000 0053 6865 6C6C 4578 32.dll...ShellEx
000006E0 6563 7574 6541 0053 4845 4C4C 3332 2E64 ecuteA.SHELL32.d
000006F0 6C6C 0000 0000 0000 0000 0000 0000 0000 ll..............
00000700 0000 0000 0000 0000 0000 0000 0000 0000 ................
00000710 0000 0000 0000 0000 0000 0000 0000 0000 ................
000007......                  
000007F0 0000 0000 0000 0000 0000 0000 0000 0000 ................


On va se débrouiller à partir de ça.

On peut déjà remettre les RVAs de la structure IMAGE_IMPORT_DESCRIPTOR qui pointent sur le nom de chaque DLL. Ca c'est directe.
On peut aussi remplir les RVA des structures ORIGINAL_FIRST_THUNK et FIRST_THUNK qui pointent sur les noms des fonctions (enfin 1 WORD avant à cause du N°Ordinal) C'est ce que je viens de faire au-dessus.

C'est parti...

00000600     0000 0000 FFFF FFFF B120 0000  
00000610         0000 0000 FFFF FFFF  
00000620 CC20 0000         0000 0000  
00000630 FFFF FFFF E720 0000     0000 0000  
00000640 0000 0000 0000 0000 0000 0000 0000 0000  
00000650 9020 0000 9E20 0000 0A01 0080 0000 0000  
00000660 BE20 0000 0000 0000 D720 0000 0000 0000  
00000670 9020 0000 9E20 0000 0A01 0080 0000 0000  
00000680 BE20 0000 0000 0000 D720 0000 0000 0000  
00000690 7500 4578 6974 5072 6F63 6573 7300 0000 u.ExitProcess...
000006A0 4765 744D 6F64 756C 6548 616E 646C 6541 GetModuleHandleA
000006B0 004B 4552 4E45 4C33 322E 646C 6C00 BB01 .KERNEL32.dll...
000006C0 4D65 7373 6167 6542 6F78 4100 5553 4552 MessageBoxA.USER
000006D0 3332 2E64 6C6C 0000 0053 6865 6C6C 4578 32.dll...ShellEx
000006E0 6563 7574 6541 0053 4845 4C4C 3332 2E64 ecuteA.SHELL32.d
000006F0 6C6C 0000 0000 0000 0000 0000 0000 0000 ll..............
00000700 0000 0000 0000 0000 0000 0000 0000 0000 ................
00000710 0000 0000 0000 0000 0000 0000 0000 0000 ................
000007......                  
000007F0 0000 0000 0000 0000 0000 0000 0000 0000 ................

Comment ça : "d'où il vient le dword 0A01 0080 ???? "
Vous vous souvenez que FT_Exit8 on l'importe By Ordinal et que son n° est 10Ah soit 0000 010Ah mais justement parce que c'est une fonction importée By Ordinal on le notifie en mettant son MSB à 1 (son byte de poids fort à 1) [1000.......... binaire soit 8........ hexadécimal]
soit 8000 010Ah et vu au format Intel ça donne bien 0A01 0080 et ce n°Ordinal remplace le RVA qui pointe normalement sur son nom.

Maintenant, on peut finir de remplir IMAGE_IMPORT_DESCRIPTOR (OriginalFirstThunk et FirstThunk)

00000600 5020 0000 0000 0000 FFFF FFFF B120 0000  
00000610 7020 0000 6020 0000 0000 0000 FFFF FFFF  
00000620 CC20 0000 8020 0000 6820 0000 0000 0000  
00000630 FFFF FFFF E720 0000 8820 0000 0000 0000  
00000640 0000 0000 0000 0000 0000 0000 0000 0000  
00000650 9020 0000 9E20 0000 0A01 0080 0000 0000  
00000660 BE20 0000 0000 0000 D720 0000 0000 0000  
00000670 9020 0000 9E20 0000 0A01 0080 0000 0000  
00000680 BE20 0000 0000 0000 D720 0000 0000 0000  
00000690 7500 4578 6974 5072 6F63 6573 7300 0000 u.ExitProcess...
000006A0 4765 744D 6F64 756C 6548 616E 646C 6541 GetModuleHandleA
000006B0 004B 4552 4E45 4C33 322E 646C 6C00 BB01 .KERNEL32.dll...
000006C0 4D65 7373 6167 6542 6F78 4100 5553 4552 MessageBoxA.USER
000006D0 3332 2E64 6C6C 0000 0053 6865 6C6C 4578 32.dll...ShellEx
000006E0 6563 7574 6541 0053 4845 4C4C 3332 2E64 ecuteA.SHELL32.d
000006F0 6C6C 0000 0000 0000 0000 0000 0000 0000 ll..............
00000700 0000 0000 0000 0000 0000 0000 0000 0000 ................
00000710 0000 0000 0000 0000 0000 0000 0000 0000 ................
000007......                  
000007F0 0000 0000 0000 0000 0000 0000 0000 0000 ................

 

 


Bon, on a un IAT propre, mais pas fonctionnel. On n'a pas redirigé le membre Import Table, Ben oui on a déplacé IMAGE_IMPORT_DESCRIPTOR en début de section donc on reprend ProcDump et on donne la même valeur à Import Table que celle de Import Address Table (2000h)

 

Voilà, l'IAT est fonctionnel, et pour en être sûr il ne reste plus qu'à utiliser W32Dasm si il trouve des modules importés et toutes les fonctions, c'est gagné

+++++++++++++++++++ IMPORTED FUNCTIONS ++++++++++++++++++
Number of Imported Modules = 3 (decimal)

Import Module 001: KERNEL32.dll
Import Module 002: USER32.dll
Import Module 003: SHELL32.dll

+++++++++++++++++++ IMPORT MODULE DETAILS +++++++++++++++

Import Module 001: KERNEL32.dll

Addr:00002090 hint(0075) Name: ExitProcess
Addr:0000209E hint(0000) Name: GetModuleHandle <------------- on lui avait pas donné de valeur pour son ordinal
Addr:8000010A hint(010A) Name: FT_Exit8 <--------------------- grâce à son ordinal on a bien retrouvé son nom (8000 ....)

Import Module 002: USER32.dll

Addr:000020BD hint(01BB) Name: MessageBoxA

Import Module 003: SHELL32.dll

Addr:000020D6 hint(0000) Name: ShellExecute <--------------- lui non plus, et pourtant ça marche vous voyez.

 

 

 


AAAAAAHHH !!!!!!!!! LE PROGRAMME NE FONCTIONNE PLUS !!!!!!!!!!!

C'est normal, on a tout chamboulé dans l'IAT, et la section code (.text) va chercher directemment des info dedans. Ca signifie qu'on à détruit les relations qui existent entre le code et l'IAT. Reprenez le programme d'origine tout en bas on trouve deux

FF25......... jump dword ptr [.......]

Ce qui se trouve entre parenthèse c'est le RVA contenu dans le membre FirstThunk de IMAGE_IMPORT_DESCRIPTOR (+ l'ImageBase)
Autrement dit, c'est le RVA qui pointe sur la structure IMAGE_IMPORT_BY_NAME des ces fonctions en question.

initialement on avait:



* Reference To: USER32.MessageBoxA, Ord:01BBh
|
:0040101C FF2508204000 Jmp dword ptr [00402008] donc 2008 soit 0820

* Reference To: KERNEL32.ExitProcess, Ord:0075h
|
:00401022 FF2500204000 Jmp dword ptr [00402000] donc 2000h soit 0020

 

Reprenons notre tableau, ils sont maintenant à :

7020 pour ExitProcess soit 2070--->00402070
7420 pour GetModuleHandleA soit 2074 --->00402074
7820 pour FT_Exit8 soit 2078 ---> 00402078

8020 pour MessageBoxA soit 2080 ---> 00402080

8820 pour ShellExcuteA soit 2088 ---> 00402088


Il faut donc effectuer une petite réparation.

On recherche avec HexWorkShop

Recherche de: Remplacement par
FF2508204000 (MessageBoxA) FF2580204000
FF2500204000 (ExitProcess) FF2570204000

 

Oufff ça Marche!!!

Le programme refonctionne, et on a trois nouvelles fonctions à disposition dans l'IAT. Il y a deux façons d'appeler les nouvelles fonctions. Soit vous créez des
[AdresseX] FF25......jmp dword ptr [........] en fin de code et un simple Call AdresseX appelera votre fonction

Soit vous pouvez l'appeler directement en l'appelant ainsi : Call dword ptr [.........]
Le contenu du jmp ou du call étant l'ImageBase + FirstThunk bien entendu. (Mais surtout pas OriginalFirstThunk)

 


Par Morgatte